import sys
from threading import Thread

import pygame,traceback
from pygame.locals import *

from lib.scripts.AStart_Path import *
from lib.scripts.GameDuel import *
from lib.scripts.Enemys import *
from lib.scripts.GameEffect import *
from lib.scripts.GameInit import *
from lib.scripts.GameLoad import *
from lib.scripts.GC import *
from lib.scripts.Hero import *
from lib.scripts.MapLogic import *
from lib.scripts.MonsterHandbook import *
from lib.scripts.GameMusic import *
from lib.scripts.Package import *
from lib.scripts.ui.font import *
from lib.scripts.ui.GameSetting import *
from lib.scripts.ui.ShowDiaLog import *
from map.mapManage.mapMgr import *

class Run:
    def __init__(self,w,h,t,fps=50,form=None) -> None:
        pygame.init()
        self.win_w = w
        self.win_h = h
        self.fps = fps
        pygame.display.set_caption(t,"icon?")
        self.win = pygame.display.set_mode((w,h))
        pygame.display.set_icon(pygame.image.load(r"lib\images\title.png"))
        self.clock = pygame.time.Clock()
        # 通过编辑器启动时, form == 编辑器, 直接通过main启动游戏 form始终为 None
        self.form = form

        self.__this_init__()

    def __this_init__(self):
        # 初始化GC
        GC._loadGC()
        ShowDiaLog.main = self
        self.GameFont = GameFont(self)
        self.GameLoad = GameLoad(self)
        # 避免启动等待时间过长,使用多线程加载资源, 窗口先显示出来
        Thread(target=self.GameLoad._GameInit,daemon=True).start()
        self.runGame()

    def _GameInit(self):
        try:
            self.GInit = GameInit()
            self.mapLogic = MapLogic(self)
            self.GameMusic = Music(self)
            self.GameBag = Package(self)
            self.evHandle = EvHandle(self.mapLogic,self.GameMusic,self.GameBag)
            self.hero = Hero(self)
            self.MonsterBook = MonsterHandbook(self)
            # 战斗事件
            self.GameDuel = Duel(self)
            self.GameEff = Effect(self)
            # 游戏设置
            self.GameSetting = Setting(self)
            
            # 渲染帧率
            self.fpsStr = ""
            # 
            self.GameLoad.tips = "加载完成!!"
            self.GameLoad.loadLevel = 1
            self.GameMusic._load()
        except:
            errorLog = traceback.format_exc()
            print_error(errorLog)

    def runGame(self) -> None:
        while True:
            self.clock.tick(self.fps)
            if not self.GameLoad.isActive:
                self.win.fill((150,150,150))
                self.GameLogic()
                self.GameRender()
                self.GameRenderMask()
            else:
                self.GameLoad.render()
            # 提示信息的优先级最高
            ShowDiaLog.renderTips()
            pygame.display.update()

    def GameEvent(self):
        """游戏事件"""
        pos = pygame.mouse.get_pos()
        # 是否激活了背包,此时只能触发背包区域的事件
        if self.GameBag.isActive() or self.MonsterBook.isActive() or self.GameSetting.isActive():
            return
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                self.GameQuit()
                return
            elif e.type == pygame.MOUSEBUTTONDOWN:
                if pygame.mouse.get_pressed() == (1,0,0):
                    # 判断是否触发了ui弹窗
                    if ShowDiaLog.isActive:
                        self.evHandle._execEvent()
                        return
                    mapPos = (int(pos[1])//32,(pos[0]-200)//32)
                    # 判断是否超出了地图区域
                    if mapPos[0] <= 13 and mapPos[0] >=0 and mapPos[1] <= 13 and  mapPos[1] >=0:
                        # 如果当前正在战斗, 那么禁止寻路
                        if self.GameDuel.isActive():
                            # 如果战斗没结束,不执行,否则关闭ui
                            if self.GameDuel.duelOver:
                                return
                            self.GameDuel.closeDuelUI()
                        self.hero.map2D = self.mapLogic.getFloor(self.mapLogic.floorName)
                        aStar = AStar(self.hero.map2D,Point(self.hero.localPos[1],self.hero.localPos[0]),Point(mapPos[0],mapPos[1]))
                        #开始寻路
                        path:list[Point] = aStar.start()
                        if not path is None:
                            self.hero.go(path[0].y,path[0].x,path)
                        return
                        
            elif e.type == pygame.KEYDOWN:
                if e.key == K_RETURN:
                    # 判断是否触发了ui弹窗
                    if ShowDiaLog.isActive:
                        self.evHandle._execEvent()
                        return
                elif e.key == K_b:
                    # 如果触发了事件,那么先暂时禁止打开背包
                    if not ShowDiaLog.isActive:
                        self.GameBag.ShowUI()
                elif e.key == K_x:
                    # 如果触发了事件,那么先暂时禁止打开怪物手册
                    if not ShowDiaLog.isActive:
                        self.MonsterBook.ShowUI()

                # 可以通过 Esc 按钮继续往下触发对话
                elif e.key == K_ESCAPE:
                    # 判断是否触发了ui弹窗
                    if ShowDiaLog.isActive:
                        self.evHandle._execEvent()
                        return
                    else:
                        self.GameSetting.ShowUI()

    def GameRender(self):
        """渲染游戏逻辑事件层"""
        # 渲染主角
        self.hero.render()
        # 对话弹窗的优先级较低
        ShowDiaLog.render()
        # 战斗面板
        self.GameDuel.render()
        # 特效优先级高于战斗面板
        self.GameEff.render()
        # 背包优先级较高
        self.GameBag.render()
        # 怪物手册
        self.MonsterBook.render()
        # 游戏设置面板
        self.GameSetting.render()

    def GameRenderMask(self):
        """渲染游戏遮罩层(天空层)"""
        pass

    def GameLogic(self):
        """游戏逻辑"""
        # 实现部分游戏特性的延时效果
        self.GInit.delay = (self.GInit.delay -1) % 100
            
        """计算fps"""
        self.fpsStr = f"fps:{int(self.clock.get_fps())}"
        # 渲染地图
        map2d = self.mapLogic.getFloor(self.mapLogic.floorName)
        for y in range(len(map2d)):
            for x in range(len(map2d[y])):
                sceneX = y*32 +200
                sceneY = x*32
                GBlock =  GC.GC_SourceMgr.get(str(map2d[x][y]))
                # 渲染地板
                self.win.blit(GC.GC_GameSurfaceCache.get("terrains"),(sceneX,sceneY),(0,0,32,32))
                if not GBlock is None:
                    posStr = f"{y}-{x}"
                    # 根据缓存的图块精灵进行渲染,如果遇到需要操作地图的图块时,需要将缓存对应的图块坐标删除,或者将整个缓存全部清空
                    BSprite = self.GInit.FBCache.get(posStr)
                    if BSprite is None:
                        if GBlock["type"] == "enemys":
                            monster = Enemys(self,GBlock,x,y)
                            GC.GC_FloorMonsterData[monster.key] = monster
                            self.GInit.FBCache[posStr] = monster
                        else:
                            self.GInit.FBCache[posStr] = BlockSprite(GC.GC_GameSurfaceCache.get(GBlock["type"]),GBlock,mg=self.mapLogic)
                            self.GInit.FBCache[posStr].objectName = [x,y]
                        BSprite = self.GInit.FBCache[posStr]
                    BSprite.update(self,sceneX,sceneY)

        self.GameEvent()

    def GameQuit(self):
        """退出程序"""
        if not self.form is None:
            self.form.RunGame = False
        pygame.quit()
        sys.exit()